use std::iter;
use std::vec::IntoIter;

// 1.该函数组合了两个`Vec<i32>`并在其返回一个迭代器
// 返回类型确实复杂
fn combine_vecs_explicit_return_type(
    v: Vec<i32>,
    u: Vec<i32>,
) -> iter::Cycle<iter::Chain<IntoIter<i32>, IntoIter<i32>>> {
    v.into_iter().chain(u.into_iter()).cycle()
}
// 通过`impl trait`语法,实现上述函数且简单明了
fn combine_vecs(v: Vec<i32>, u: Vec<i32>) -> impl Iterator<Item=i32> {
    v.into_iter().chain(u.into_iter()).cycle()
}

// 2.某些 Rust 类型无法写出。例如，每个闭包都有自己未命名的具体类型。
// 在使用 impl Trait 语法之前，必须在堆上进行分配才能返回闭包。
// 但是现在你可以像下面这样静态地完成所有操作
fn add_fn(y: i32) -> impl Fn(i32) -> i32 {
    move |x: i32| x + y
}
// 3.还可以使用 impl Trait 返回使用 map 或 filter 闭包的迭代器！
// 这使得使用 map 和 filter 更容易。因为闭包类型没有名称，所以如果函数返回带闭包的迭代器，
// 则无法写出显式的返回类型。但是有了 impl Trait，你就可以轻松地做到
fn double_positives<'a>(num: &'a Vec<i32>) -> impl Iterator<Item = i32> + 'a {
    num
    .iter()
    .filter(|x| **x > 0)
    .map(|x| x * 2)
}
fn main() {
//    使用`impl trait`签名函数
    let v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];
    let v3 = combine_vecs_explicit_return_type(v1.clone(), v2.clone());
    for v in &mut v3.take(6) {
        println!("{}", v);
    }
    let mut v4 = combine_vecs(v1, v2);
    assert_eq!(v4.next(), Some(1));
    assert_eq!(v4.next(), Some(2));
    assert_eq!(v4.next(), Some(3));
    assert_eq!(v4.next(), Some(4));
//     2.返回一个将输入和`y`相加的函数
    println!("2.返回一个将输入和`y`相加的函数");
    let plus_one = add_fn(1);
    println!("{}", plus_one(2));
    assert_eq!(plus_one(2), 3);
//     3.返回使用 map 或 filter 闭包的迭代器
    println!("3.返回使用 map 或 filter 闭包的迭代器");
    let binding = vec![-1, 2, 4, -5, 3];
    let v5 = double_positives(&binding);
    println!("{:?}", Some(v5).expect("REASON").next());
    for v in double_positives(&binding) {
        println!("{}", v);
    }
    let mut v6 = double_positives(&binding);
    assert_eq!(v6.next(), Some(4));
    assert_eq!(v6.next(), Some(8));
    assert_eq!(v6.next(), Some(6));
}
